package com.hailiang.study.javase.java.util;

import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * @author hailiang.jiang
 * @date 2022年05月10 15:52
 */
public class Collectors_groupBy {

    private List<Person> personList = new ArrayList<>();

    @Before
    public void init() {
        List<String> cityList = Arrays.asList("北京", "上海", "广州", "深圳");
        for (int i = 8; i > 0; i--) {
            Random random = new Random();
            int cityIdx = random.nextInt(4);
            String province = cityList.get(cityIdx);
            String name = "姓名_" + i;
            int age = 20 + cityIdx;
            Person person = new Person(province, name, age);
            personList.add(person);
        }
    }

    @Test
    public void test_groupingBys() {
        Map<String, Map<Integer, List<Person>>> collect = personList.stream().collect(Collectors.groupingBy(Person::getProvince, Collectors.groupingBy(Person::getAge)));

        collect.forEach((k, v) -> {
            System.out.println(k + " = " + v);
            v.forEach((i, j) -> {
                System.out.println(i + " = " + j);
            });
        });
    }

    @Test
    public void test_groupingByDistinct() {
        System.out.println(personList.stream().filter(distinctByKey(Person::getProvince)).collect(Collectors.toList()));
    }

    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Set<Object> seen = ConcurrentHashMap.newKeySet();
        return t -> seen.add(keyExtractor.apply(t));
    }

    static class Person {
        private String province;
        private String name;
        private int age;

        public Person(String province, String name, int age) {
            this.province = province;
            this.name = name;
            this.age = age;
        }

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "province='" + province + '\'' +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}
